/*********************************************************************************
 *      Copyright:  (C) 2025 chenhongyu IOT STUDY
 *                  All rights reserved.
 *
 *       Filename:  mqtt.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(17/07/25)
 *         Author:  chenhongyu <chenhongyu0822@163.com>
 *      ChangeLog:  1, Release initial version on "17/07/25 22:42:07"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mosquitto.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>

#include "mqtt.h"
#include "main.h"

#define  MQTT_HOST              "8.148.223.28"
#define  MQTT_PORT              1883
#define  MQTT_CLIENT_ID         "001"
#define  MQTT_USERNAME          "testuser"
#define  MQTT_PASSWORD          "123456"
#define  MQTT_TOPIC_DATA        "max30102"
#define  MQTT_TOPIC_CMD         "mqtt/cmd"



static struct mosquitto *mosq = NULL;

struct mosquitto *mqtt_get_client() 
{
    return mosq;
}


void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
	bled_t         *ctx=(bled_t *)userdata;
	size_t         copy_len;
	ble_ctx        *ble = &ctx->ble;

	syslog(LOG_INFO,"Received message on topic %s: %s\n", message->topic, (char *)message->payload);

	if (ctx && message->payload && (message->payloadlen > 0)) 
	{
		copy_len = message->payloadlen;
        memcpy(ble->cmd_buf, message->payload, copy_len);
		ble->cmd_buf[copy_len] = '\0';
		ble->has_cmd = 1;
    }

}

int mqtt_connect(bled_t *ctx)
{
    int                   rc;

    mosquitto_lib_init();
    mosq = mosquitto_new(ctx->mqtt.client_id, true, NULL);
    if (!mosq)
    {
		syslog(LOG_ERR,"mosquitto_new faliure:%s.\n", strerror(errno));
        return -1;
    }

	mosquitto_user_data_set(mosq, ctx);

    mosquitto_message_callback_set(mosq, on_message); 

    if (ctx->mqtt.username && ctx->mqtt.password)
    {
        mosquitto_username_pw_set(mosq, ctx->mqtt.username, ctx->mqtt.password);
    }

    rc = mosquitto_connect(mosq, ctx->mqtt.host, ctx->mqtt.port, 60);
    if (rc != MOSQ_ERR_SUCCESS)
    {
		syslog(LOG_ERR, "MQTT connect error:%s.\n", strerror(errno));
        mosquitto_destroy(mosq);
        mosquitto_lib_cleanup();
        mosq = NULL;
        return -2;
    }

    rc = mosquitto_subscribe(mosq, NULL, ctx->mqtt.topic_cmd, 0); 
    if (rc != MOSQ_ERR_SUCCESS)
    {
		syslog(LOG_ERR, "MQTT subscribe error:%s.\n", strerror(errno));
        return -3;
    }

    return 0;
}

int mqtt_publish(const char *topic, const uint8_t *buf, size_t len)
{
	int                rc;
    
	if (!mosq)
    {
		syslog(LOG_ERR, "MQTT client not connected:%s.\n", strerror(errno));
        return -1;
    }

    rc = mosquitto_publish(mosq, NULL, topic, len, buf, 0, false);
    if (rc != MOSQ_ERR_SUCCESS)
    {
		syslog(LOG_ERR, "MQTT publish error:%s.\n", strerror(errno));
        return -2;
    }

    syslog(LOG_INFO, "MQTT published: %.*s\n", (int)len, buf); 
    return 0;
}

void mqtt_cleanup()
{
    if (mosq)
    {
        mosquitto_disconnect(mosq);
        mosquitto_destroy(mosq);
        mosq = NULL;
    }

    mosquitto_lib_cleanup();
}


void *mqtt_thread(void *arg)
{

	struct mosquitto              *mosq;
	int                           rv;	
	int                           loop_rc;
	mqtt_ctx                      *mqtt=&((bled_t *)arg)->mqtt;
	ble_ctx                       *ble = &((bled_t *)arg)->ble;

	mqtt->host      = MQTT_HOST;
	mqtt->port      = MQTT_PORT;
	mqtt->client_id = MQTT_CLIENT_ID;
	mqtt->username  = MQTT_USERNAME;
	mqtt->password  = MQTT_PASSWORD;
	mqtt->topic_data= MQTT_TOPIC_DATA;
	mqtt->topic_cmd = MQTT_TOPIC_CMD;
    
	syslog(LOG_INFO, "Initializing MQTT connection to broker: %s:%d\n", mqtt->host, mqtt->port);

	rv=mqtt_connect((bled_t *)arg);
    if(rv<0)
    {
        syslog(LOG_ERR, "Failed to initialize MQTT:%s\n", rv);
		return NULL;
    }
	syslog(LOG_INFO, "MQTT connection established successfully.\n");

	mosq = mqtt_get_client();
    mqtt->mosq=mosq;

	syslog(LOG_INFO, "Starting MQTT main loop...\n");
	while(1)
	{
		loop_rc=mosquitto_loop(mqtt->mosq, -1, 1);
		if (loop_rc != MOSQ_ERR_SUCCESS)
        {
            syslog(LOG_WARNING,"MQTT loop warning: %s\n", mosquitto_strerror(loop_rc));
        }

		if(ble->recv_len>0)
		{
			syslog(LOG_INFO, "Publishing BLE data to MQTT topic '%s'\n", mqtt->topic_data);
			
			if(mqtt_publish(mqtt->topic_data, ble->recv_buf, ble->recv_len)<0)
			{
				printf("Publishing BLE data to MQTT faliure:%s\n", strerror(errno));
			}

			ble->recv_len = 0;
		}
		usleep(100);
	}
	return NULL;
}

